package com.example.vaultmysql.service;

import com.example.vaultmysql.dto.DatabaseCredentials;
import com.example.vaultmysql.dto.DatabaseConnectionTestResult;
import com.example.vaultmysql.entity.DatabaseConfig;
import com.example.vaultmysql.entity.ConnectionPool;
import com.example.vaultmysql.repository.DatabaseConfigRepository;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 数据库连接服务
 * 负责管理多个数据库的连接池
 * 
 * @author System
 * @version 1.0.0
 */
@Slf4j
@Service
public class DatabaseConnectionService {

    @Autowired
    private VaultService vaultService;

    @Autowired
    private DatabaseConfigRepository databaseConfigRepository;

    // 数据库连接池缓存
    private final Map<String, HikariDataSource> dataSourceCache = new ConcurrentHashMap<>();

    /**
     * 获取数据库连接
     */
    public Connection getConnection(String databaseName) throws SQLException {
        HikariDataSource dataSource = getDataSource(databaseName);
        if (dataSource == null) {
            throw new SQLException("无法获取数据库连接池: " + databaseName);
        }
        return dataSource.getConnection();
    }

    /**
     * 获取数据源
     */
    public DataSource getDataSource(String databaseName) {
        // 先从缓存中获取
        HikariDataSource dataSource = dataSourceCache.get(databaseName);
        if (dataSource != null && !dataSource.isClosed()) {
            return dataSource;
        }

        // 缓存中没有，创建新的连接池
        synchronized (this) {
            // 双重检查
            dataSource = dataSourceCache.get(databaseName);
            if (dataSource != null && !dataSource.isClosed()) {
                return dataSource;
            }

            try {
                dataSource = createDataSource(databaseName);
                if (dataSource != null) {
                    dataSourceCache.put(databaseName, dataSource);
                    log.info("成功创建数据库连接池: {}", databaseName);
                }
                return dataSource;
            } catch (Exception e) {
                log.error("创建数据库连接池失败: database={}, error={}", databaseName, e.getMessage());
                return null;
            }
        }
    }

    /**
     * 创建数据源
     */
    private HikariDataSource createDataSource(String databaseName) throws Exception {
        // 获取数据库配置
        DatabaseConfig dbConfig = databaseConfigRepository.findByName(databaseName)
                .orElseThrow(() -> new IllegalArgumentException("数据库配置不存在: " + databaseName));

        if (!dbConfig.getEnabled()) {
            throw new IllegalStateException("数据库已禁用: " + databaseName);
        }

        // 从Vault获取凭证
        DatabaseCredentials credentials = vaultService.getDatabaseCredentials(dbConfig.getVaultPath());
        if (!credentials.isValid()) {
            throw new IllegalStateException("数据库凭证无效: " + databaseName);
        }

        // 创建HikariCP配置
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(dbConfig.getJdbcUrl());
        config.setUsername(credentials.getUsername());
        config.setPassword(credentials.getPassword());
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");

        // 设置连接池参数
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);
        config.setAutoCommit(true);

        // 设置连接池名称
        config.setPoolName("HikariPool-" + databaseName);

        // 设置连接测试查询
        config.setConnectionTestQuery("SELECT 1");

        // 设置连接属性
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.addDataSourceProperty("useServerPrepStmts", "true");
        config.addDataSourceProperty("useLocalSessionState", "true");
        config.addDataSourceProperty("rewriteBatchedStatements", "true");
        config.addDataSourceProperty("cacheResultSetMetadata", "true");
        config.addDataSourceProperty("cacheServerConfiguration", "true");
        config.addDataSourceProperty("elideSetAutoCommits", "true");
        config.addDataSourceProperty("maintainTimeStats", "false");

        return new HikariDataSource(config);
    }

    /**
     * 测试数据库连接
     */
    public DatabaseConnectionTestResult testConnection(String databaseName) {
        return testConnection(databaseName, true);
    }

    /**
     * 测试数据库连接
     */
    public DatabaseConnectionTestResult testConnection(String databaseName, boolean useVault) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 获取数据库配置
            DatabaseConfig dbConfig = databaseConfigRepository.findByName(databaseName)
                    .orElseThrow(() -> new IllegalArgumentException("数据库配置不存在: " + databaseName));

            if (!dbConfig.getEnabled()) {
                return DatabaseConnectionTestResult.failure(
                    "数据库已禁用", 
                    System.currentTimeMillis() - startTime
                );
            }

            DatabaseCredentials credentials = null;
            if (useVault) {
                // 从Vault获取凭证
                credentials = vaultService.getDatabaseCredentials(dbConfig.getVaultPath());
                if (!credentials.isValid()) {
                    return DatabaseConnectionTestResult.failure(
                        "数据库凭证无效", 
                        System.currentTimeMillis() - startTime
                    );
                }
            }

            // 创建测试连接
            HikariConfig config = new HikariConfig();
            config.setJdbcUrl(dbConfig.getJdbcUrl());
            
            if (useVault && credentials != null) {
                config.setUsername(credentials.getUsername());
                config.setPassword(credentials.getPassword());
            } else {
                // 使用默认测试凭证
                config.setUsername("test");
                config.setPassword("test");
            }
            
            config.setDriverClassName("com.mysql.cj.jdbc.Driver");
            config.setMaximumPoolSize(1);
            config.setConnectionTimeout(10000);
            config.setConnectionTestQuery("SELECT 1");

            try (HikariDataSource testDataSource = new HikariDataSource(config);
                 Connection connection = testDataSource.getConnection()) {
                
                // 执行测试查询
                connection.createStatement().executeQuery("SELECT 1").close();
                
                long connectionTime = System.currentTimeMillis() - startTime;
                
                return DatabaseConnectionTestResult.success(
                    "连接成功", 
                    connectionTime
                );
            }
            
        } catch (Exception e) {
            long connectionTime = System.currentTimeMillis() - startTime;
            log.error("数据库连接测试失败: database={}, error={}", databaseName, e.getMessage());
            
            return DatabaseConnectionTestResult.failure(
                "连接失败: " + e.getMessage(), 
                connectionTime
            );
        }
    }

    /**
     * 关闭数据库连接池
     */
    public void closeDataSource(String databaseName) {
        HikariDataSource dataSource = dataSourceCache.remove(databaseName);
        if (dataSource != null && !dataSource.isClosed()) {
            dataSource.close();
            log.info("关闭数据库连接池: {}", databaseName);
        }
    }

    /**
     * 关闭所有数据库连接池
     */
    public void closeAllDataSources() {
        for (Map.Entry<String, HikariDataSource> entry : dataSourceCache.entrySet()) {
            HikariDataSource dataSource = entry.getValue();
            if (dataSource != null && !dataSource.isClosed()) {
                dataSource.close();
                log.info("关闭数据库连接池: {}", entry.getKey());
            }
        }
        dataSourceCache.clear();
    }

    /**
     * 获取连接池状态
     */
    public Map<String, Object> getConnectionPoolStatus(String databaseName) {
        HikariDataSource dataSource = dataSourceCache.get(databaseName);
        if (dataSource == null || dataSource.isClosed()) {
            return Map.of(
                "exists", false,
                "status", "未创建"
            );
        }

        return Map.of(
            "exists", true,
            "status", "运行中",
            "activeConnections", dataSource.getHikariPoolMXBean().getActiveConnections(),
            "idleConnections", dataSource.getHikariPoolMXBean().getIdleConnections(),
            "totalConnections", dataSource.getHikariPoolMXBean().getTotalConnections(),
            "threadsAwaitingConnection", dataSource.getHikariPoolMXBean().getThreadsAwaitingConnection()
        );
    }

    /**
     * 刷新连接池（重新创建）
     */
    public void refreshDataSource(String databaseName) {
        closeDataSource(databaseName);
        // 下次获取时会自动重新创建
        log.info("刷新数据库连接池: {}", databaseName);
    }
}